package indi.lqzhi.basic.tools;

import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.app.usage.UsageStats;
import android.app.usage.UsageStatsManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.provider.Settings;

import androidx.annotation.Nullable;

import com.blankj.utilcode.util.ActivityUtils;
import com.blankj.utilcode.util.LogUtils;
import com.blankj.utilcode.util.ThreadUtils;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.text.DecimalFormat;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

import indi.lqzhi.basic.BasicApp;
import indi.lqzhi.basic.tools.lambda.OnThreadBackground;
import indi.lqzhi.basic.tools.lambda.OnThreadCancel;
import indi.lqzhi.basic.tools.lambda.OnThreadFail;
import indi.lqzhi.basic.tools.lambda.OnThreadSucess;
import indi.lqzhi.basic.tools.thirdparty.ThreadTaskTools;


public final class Tools {

    private Tools(){
        throw new UnsupportedOperationException("Tools no need to instantiate!");
    }

    private static final DecimalFormat decimalFormatTwo = new DecimalFormat(".00");
    //构造方法的字符格式这里如果小数不足1位,会以0补足.
    public static final DecimalFormat decimalFormatOne = new DecimalFormat(".0");

    /**
     * 线程睡眠
     * @param millis 睡眠的毫秒数
     */
    public static void sleep(long millis) {
        try {
            Thread.sleep(millis);
        } catch (InterruptedException e) {
            LogUtils.e("线程 "+Thread.currentThread().getName() + "睡眠异常.异常原因:"+e.getMessage());
        }
    }

    /* #######################################Convert Tools#########################################*/

    /**
     * 判断是否为Float类型
     * @param str 需要判断的字符串
     * @return 返回结果
     */
    public static boolean isFloat(String str){
        try {
            Float.parseFloat(str);
        }catch (Exception exception){
            return false;
        }
        return true;
    }

    /**
     * 转化为为Float类型
     * @param str 需要转换的字符串
     * @return 返回结果
     */
    public static Float toFloat(String str){
        try {
            return Float.valueOf(str);
        }catch (Exception exception){
            return Float.MAX_VALUE;
        }
    }

    /**
     * 转化为为Float类型
     * @param str 需要转换的字符串
     * @param defaultValue 默认值
     * @return 返回结果
     */
    public static Float toFloat(String str,Float defaultValue){
        try {
            return Float.valueOf(str);
        }catch (Exception exception){
            return defaultValue;
        }
    }

    /**
     * 判断是否为Double类型
     * @param str 需要判断的字符串
     * @return 返回结果
     */
    public static boolean isDouble(String str){
        try {
            Double.parseDouble(str);
        }catch (Exception exception){
            return false;
        }
        return true;
    }

    /**
     * 转化为为Double类型
     * @param str 需要转换的字符串
     * @return 返回结果
     */
    public static Double toDouble(String str){
        try {
            return Double.parseDouble(str);
        }catch (Exception exception){
            return Double.MAX_VALUE;
        }
    }

    /**
     * 转化为为Double类型
     * @param str 需要转换的字符串
     * @param defaultValue 默认值
     * @return 返回结果
     */
    public static Double toDouble(String str,Double defaultValue){
        try {
            return Double.parseDouble(str);
        }catch (Exception exception){
            return defaultValue;
        }
    }

    /**
     * 判断是否为Integer类型
     * @param str 需要判断的字符串
     * @return 返回结果
     */
    public static boolean isInt(String str){
        try {
            Integer.parseInt(str);
        }catch (Exception exception){
            return false;
        }
        return true;
    }
    /**
     * 转化为为Integer类型
     * @param str 需要转换的字符串
     * @return 返回结果
     */
    public static Integer toInt(String str){
        try {
            return Integer.parseInt(str);
        }catch (Exception exception){
            return Integer.MAX_VALUE;
        }
    }

    /**
     * 转化为为Integer类型
     * @param str 需要转换的字符串
     * @param defaultValue 默认值
     * @return 返回结果
     */
    public static Integer toInt(String str,Integer defaultValue){
        try {
            return Integer.parseInt(str);
        }catch (Exception exception){
            return Integer.MAX_VALUE;
        }
    }

    /**
     * 判断是否为Long类型
     * @param str 需要判断的字符串
     * @return 返回结果
     */
    public static boolean isLong(String str){
        try {
            Long.parseLong(str);
        }catch (Exception exception){
            return false;
        }
        return true;
    }

    /**
     * 转化为为Long类型
     * @param str 需要转换的字符串
     * @return 返回结果
     */
    public static Long toLong(String str){
        try {
            return Long.parseLong(str);
        }catch (Exception exception){
            return Long.MAX_VALUE;
        }
    }

    /**
     * 转化为为Long类型
     * @param str 需要转换的字符串
     * @param defaultValue 默认值
     * @return 返回结果
     */
    public static Long toLong(String str,Long defaultValue){
        try {
            return Long.parseLong(str);
        }catch (Exception exception){
            return defaultValue;
        }
    }

    /* #######################################Convert Tools#########################################*/


    /* #######################################UsageStats Tools#########################################*/

    private static UsageStatsManager usageStatsManager;

    private static ActivityManager activityManager;

    /**
     * 得到当前运行管理的名称
     */
    @Nullable
    public static String getCurrentUsageApplicationPackageName(){
        //取出1天内的时间在对其进行排序
        return getUsageApplicationPackageName(86400000);
    }

    /**
     * 得到时间范围内的使用对象
     * @param beginTime 开始时间
     * @param endTime 结束时间
     * @return 使用列表，可能为空列表
     */
    public static List<UsageStats> getUsageStats(long beginTime, long endTime){
        //验证权限
        if (checkPermissionForUsageStats()){
            requestAppUsagePermission();//请求权限
            return Collections.emptyList();
        }
        UsageStatsManager usageStatsManager = getUsageStatsManager();
        List<UsageStats> usageStats = usageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_BEST, beginTime, endTime);
        //拿到状态后，对其进行排序
        Collections.sort(usageStats, (statsOne, statsTwo) -> (int) (statsTwo.getLastTimeUsed() - statsOne.getLastTimeUsed()));
        return usageStats;
    }

    /**
     * 得到当前运行管理的名称
     */
    @Nullable
    public static String getUsageApplicationPackageName(long fristTime){
        long time = System.currentTimeMillis();
        List<UsageStats> usageStats = getUsageStats(time - fristTime, time);
        if (usageStats.isEmpty()){
            return null;
        }
        //排序后
        return usageStats.get(0).getPackageName();
    }

    /**
     * 得到使用状态管理器
     * @return 使用状态管理器
     */
    public static UsageStatsManager getUsageStatsManager(){
        if (usageStatsManager == null){
            synchronized (UsageStatsManager.class){
                if (usageStatsManager == null){
                    usageStatsManager = (UsageStatsManager) BasicApp.getApp().getSystemService(Context.USAGE_STATS_SERVICE);//得到UsageStatsManager
                }
            }
        }
        return usageStatsManager;
    }

    /**
     * 得到使用状态管理器
     * @return 使用状态管理器
     */
    public static ActivityManager getActivityManager(){
        if (activityManager == null){
            synchronized (ActivityManager.class){
                if (activityManager == null){
                    activityManager = (ActivityManager)BasicApp.getApp().getSystemService(Context.ACTIVITY_SERVICE);
                }
            }
        }
        return activityManager;
    }

    /**
     * 检查是否具有UsageStats的权限
     * @return true 有 false 没有
     */
    public static boolean checkPermissionForUsageStats(){
        //默认初值
        try {
            BasicApp context = BasicApp.getApp();
            PackageManager packageManager = context.getPackageManager();
            ApplicationInfo applicationInfo = packageManager.getApplicationInfo(context.getPackageName(), 0);
            AppOpsManager appOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
            int mode = appOpsManager.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS, applicationInfo.uid, applicationInfo.packageName);
            return mode != AppOpsManager.MODE_ALLOWED;
        } catch (PackageManager.NameNotFoundException e) {
            return true;
        }
    }

    public static boolean requestAppUsagePermission() {
        Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        return ActivityUtils.startActivity(intent);
    }


    public static boolean checkPermissionForSystemWindows(){
        //默认初值
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            return !Settings.canDrawOverlays(ActivityUtils.getTopActivity());
        }
        return false;
    }

    public static boolean requestAppUsageSystemWindows() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            return ActivityUtils.startActivity(intent);
        }
        return true;
    }

    /* #######################################View Tools#########################################*/
    /* #######################################HEX Tools#########################################*/

    /**
     * 字节数组转换成十六进制字符串
     * 例如：0x1a 0x1c -> "1a1c"
     * @param bArray bytes数组
     * @return HexString 十六进制
     */
    public static String bytesToHexString(byte[] bArray) {
        StringBuilder sb = new StringBuilder(bArray.length);
        String sTemp;
        for (byte b : bArray) {
            sTemp = Integer.toHexString(0xFF & b);
            if (sTemp.length() < 2)
                sb.append(0);
            sb.append(sTemp.toUpperCase());//转成大写
        }
        return sb.toString();
    }


    /**
     * 将指定字符串src，以每两个字符分割转换为16进制形式
     * 如："2B 44 EF D9" --> byte[]{0x2B, 0x44, 0xEF, 0xD9}
     * @param src String 需要转换的字符串
     * @return byte[] 字节数组
     **/
    public static byte[] hexStringToByte(String src)  {
        src = src.replaceAll(" ", "");// 去掉空格
        byte[] ret = new byte[src.length() /2];
        byte[] tmp = src.getBytes();
        for(int i=0; i<src.length()/2; i++)  {
            ret[i] = uniteBytes(tmp[i*2], tmp[i*2+1]);
        }
        return ret;
    }

    /**
     * 将两个ASCII字符合成一个字节；
     * 如："EF"--> 0xEF
     * @param src0 byte 高位ascii
     * @param src1 byte 低位ascii
     * @return byte
     **/
    public static byte uniteBytes(byte src0, byte src1)  {
        byte _b0 = Byte.decode("0x" + new String(new byte[]{src0}));
        _b0 = (byte)(_b0 << 4);
        byte _b1 = Byte.decode("0x" + new String(new byte[]{src1}));
        byte ret = (byte)(_b0 ^ _b1);
        return ret;
    }

    /**
     * 判断是否十六进制字符串 ，若含有非16进制字符如'G'、'k'等字符都不算。
     *
     * @param str 字符串数组
     * @return true 是十六进制字符串 false 不是十六进制字符串
     */
    public static boolean isHex(String str) {
        boolean isHexFlg = true;
        int i = 0;
        char c;
        for (i = 0; i < str.length(); i++) {
            c = str.charAt(i);

            if (!(((c >= '0') && (c <= '9')) || ((c >= 'A') && (c <= 'F')) || ((c >= 'a') && (c <= 'f')) || (c == ' '))) {
                isHexFlg = false;
                break;
            }
        }
        return isHexFlg;
    }

    /**
     * 16进制byte转换为int
     * 例如：0x01 0xFF -> 511
     *
     * @param h byte 高位ascii
     * @param l byte 低位ascii
     * @return int
     */
    public static int bytesToInt(byte h ,byte l) {
        int s = 0;
        if (h >= 0) {
            s = s + h;
        } else {
            s = s + 256 + h;
        }
        s = s * 256;
        if (l >= 0) {
            s = s + l;
        } else {
            s = s + 256 + l;
        }
        return s;
    }

    /* #######################################HEX Tools#########################################*/

    /* #######################################Object Tools#########################################*/


    /**
     * 不为空
     * @param value        检查的值
     * @param defaultValue 默认值
     * @param <T>          参数
     * @return null就是默认值，否则就是原值
     */
    public static <T> T notNull(T value,T defaultValue){
        if (value == null){
            return defaultValue;
        }
        return value;
    }

    /**
     * 序列化
     * @param value 继承了Serializable接口的对象
     * @return bytes
     */
    @Nullable
    public static byte[] pickSerializable(Serializable value){
        try(ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()){
            try(ObjectOutput out = new ObjectOutputStream(byteArrayOutputStream)){
                out.writeObject(value);
                return byteArrayOutputStream.toByteArray();
            }
        }catch (IOException e){
            return null;
        }
    }


    /**
     * 反序列化
     * @param bytes 序列化的数组
     * @return 反序列化的对象
     */
    @Nullable
    public static <T extends Serializable> T unpickSerializable(byte[] bytes){
        return unpickSerializable(bytes,null);
    }

    /**
     * 反序列化
     * @param bytes 序列化的数组
     * @param defaultValue 默认值
     * @return 反序列化的对象
     */
    public static <T extends Serializable> T unpickSerializable(byte[] bytes,T defaultValue){
        try(ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes)){
            try(ObjectInput in = new ObjectInputStream(byteArrayInputStream)){
                return (T)in.readObject();
            }
        }catch (IOException | ClassNotFoundException e){
            return defaultValue;
        }
    }

    /**
     * 序列化
     * @param value 继承了Parcelable接口的对象
     * @return bytes
     */
    public static byte[] pickParcelable(Parcelable value){
        Parcel parcel = Parcel.obtain();
        value.writeToParcel(parcel, 0);
        byte[] bytes = parcel.marshall();
        parcel.recycle();
        return bytes;
    }

    /**
     * 反序列化
     * @param bytes 序列化后的数组
     * @return bytes
     */
    @Nullable
    public static <T extends Parcelable> T unpickParcelable(byte[] bytes,Class<T> tClass){
        return unpickParcelable(bytes,tClass,null);
    }

    /**
     * 反序列化
     * @param bytes 序列化后的数组
     * @return bytes
     */
    public static <T extends Parcelable> T unpickParcelable(byte[] bytes, Class<T> tClass, T defaultValue){
        Parcel parcel = Parcel.obtain();
        parcel.unmarshall(bytes, 0, bytes.length);
        parcel.setDataPosition(0); // this is extremely important!

        try {
            String name = tClass.toString();
            Parcelable.Creator<?> creator = null;

            Field field = tClass.getField("CREATOR");
            creator = (Parcelable.Creator<?>)field.get((Object)null);

            if (creator == null) {
                throw new Exception("Parcelable protocol requires a non-null static Parcelable.Creator object called CREATOR on class " + name);
            }

            Parcelable parcelable = (Parcelable)creator.createFromParcel(parcel);
            return parcelable == null ? defaultValue : (T) parcelable;
        } catch (Exception exception) {
            return defaultValue;
        } finally {
            parcel.recycle();
        }

    }

    public static <T,E extends RuntimeException> T checkNull(T checkObj,E runtimeExceptionObj) {
        //判断集合对象
        if (checkObj instanceof Collection){
            if (checkObj ==null || ((Collection)checkObj).size() == 0){
                throw runtimeExceptionObj;
            }
        }
        //判断正常对象
        if (checkObj == null){
            throw runtimeExceptionObj;
        }
        return checkObj;
    }

    /* #######################################Object Tools#########################################*/


    /* #######################################Thread Cache Tools#########################################*/

    /**
     * 运行任务到缓存线程池中
     * @param runnable 任务
     */
    public static void runTaskByCached(Runnable runnable){
        ThreadUtils.executeByCached(ThreadTaskTools.getTask(runnable));
    }

    /**
     * 运行任务到缓存线程池中
     * @param onThreadBackground 任务
     * @param onThreadSucess 成功回调
     * @param <T> 参数
     */
    public static <T> void runTaskByCached(OnThreadBackground<T> onThreadBackground, OnThreadSucess<T> onThreadSucess){
        ThreadUtils.executeByCached(ThreadTaskTools.getTask(onThreadBackground,onThreadSucess));
    }

    /**
     * 运行任务到缓存线程池中
     * @param onThreadBackground 任务
     * @param onThreadSucess 成功回调
     * @param onThreadFail 失败回调
     * @param <T> 参数
     */
    public static <T> void runTaskByCached(OnThreadBackground<T> onThreadBackground, OnThreadSucess<T> onThreadSucess, OnThreadFail onThreadFail){
        ThreadUtils.executeByCached(ThreadTaskTools.getTask(onThreadBackground,onThreadSucess,onThreadFail));
    }

    /**
     * 运行任务到缓存线程池中
     * @param onThreadBackground 任务
     * @param onThreadSucess 成功回调
     * @param onThreadCancel 线程取消回调
     * @param onThreadFail 失败回调
     * @param <T> 参数
     */
    public static <T> void runTaskByCached(OnThreadBackground<T> onThreadBackground, OnThreadSucess<T> onThreadSucess, OnThreadCancel onThreadCancel, OnThreadFail onThreadFail){
        ThreadUtils.executeByCached(ThreadTaskTools.getTask(onThreadBackground,onThreadSucess,onThreadCancel,onThreadFail));
    }


    /* #######################################Thread Cache Tools#########################################*/


    /* #######################################Thread IO  Tools#########################################*/

    /**
     * 运行任务到线程线程池中
     * @param runnable 任务
     */
    public static void runTaskByIo(Runnable runnable){
        ThreadUtils.executeByIo(ThreadTaskTools.getTask(runnable));
    }

    /**
     * 运行任务到线程线程池中
     * @param onThreadBackground 任务
     * @param onThreadSucess 成功回调
     * @param <T> 参数
     */
    public static <T> void runTaskByIo(OnThreadBackground<T> onThreadBackground, OnThreadSucess<T> onThreadSucess){
        ThreadUtils.executeByIo(ThreadTaskTools.getTask(onThreadBackground,onThreadSucess));
    }

    /**
     * 运行任务到线程线程池中
     * @param onThreadBackground 任务
     * @param onThreadSucess 成功回调
     * @param onThreadFail 失败回调
     * @param <T> 参数
     */
    public static <T> void runTaskByIo(OnThreadBackground<T> onThreadBackground, OnThreadSucess<T> onThreadSucess, OnThreadFail onThreadFail){
        ThreadUtils.executeByIo(ThreadTaskTools.getTask(onThreadBackground,onThreadSucess,onThreadFail));
    }

    /**
     * 运行任务到线程线程池中
     * @param onThreadBackground 任务
     * @param onThreadSucess 成功回调
     * @param onThreadCancel 线程取消回调
     * @param onThreadFail 失败回调
     * @param <T> 参数
     */
    public static <T> void runTaskByIo(OnThreadBackground<T> onThreadBackground, OnThreadSucess<T> onThreadSucess, OnThreadCancel onThreadCancel, OnThreadFail onThreadFail){
        ThreadUtils.executeByIo(ThreadTaskTools.getTask(onThreadBackground,onThreadSucess,onThreadCancel,onThreadFail));
    }


    /* #######################################Thread Io Tools#########################################*/

    /* #######################################Thread CPU  Tools#########################################*/

    /**
     * 运行任务到CPU线程池中
     * @param runnable 任务
     */
    public static void runTaskByCpu(Runnable runnable){
        ThreadUtils.executeByCpu(ThreadTaskTools.getTask(runnable));
    }

    /**
     * 运行任务到CPU线程池中
     * @param onThreadBackground 任务
     * @param onThreadSucess 成功回调
     * @param <T> 参数
     */
    public static <T> void runTaskByCpu(OnThreadBackground<T> onThreadBackground, OnThreadSucess<T> onThreadSucess){
        ThreadUtils.executeByCpu(ThreadTaskTools.getTask(onThreadBackground,onThreadSucess));
    }

    /**
     * 运行任务到CPU线程池中
     * @param onThreadBackground 任务
     * @param onThreadSucess 成功回调
     * @param onThreadFail 失败回调
     * @param <T> 参数
     */
    public static <T> void runTaskByCpu(OnThreadBackground<T> onThreadBackground, OnThreadSucess<T> onThreadSucess, OnThreadFail onThreadFail){
        ThreadUtils.executeByCpu(ThreadTaskTools.getTask(onThreadBackground,onThreadSucess,onThreadFail));
    }

    /**
     * 运行任务到CPU线程池中
     * @param onThreadBackground 任务
     * @param onThreadSucess 成功回调
     * @param onThreadCancel 线程取消回调
     * @param onThreadFail 失败回调
     * @param <T> 参数
     */
    public static <T> void runTaskByCpu(OnThreadBackground<T> onThreadBackground, OnThreadSucess<T> onThreadSucess, OnThreadCancel onThreadCancel, OnThreadFail onThreadFail){
        ThreadUtils.executeByCpu(ThreadTaskTools.getTask(onThreadBackground,onThreadSucess,onThreadCancel,onThreadFail));
    }


    /* #######################################Thread Io Tools#########################################*/

    /* #######################################Thread CPU  Tools#########################################*/

    /**
     * 运行任务到单次线程池中 ： 只运行执行一次任务
     * @param runnable 任务
     */
    public static void runTaskBySingle(Runnable runnable){
        ThreadUtils.executeBySingle(ThreadTaskTools.getTask(runnable));
    }

    /**
     * 运行任务到单次线程池中 ： 只运行执行一次任务
     * @param onThreadBackground 任务
     * @param onThreadSucess 成功回调
     * @param <T> 参数
     */
    public static <T> void runTaskBySingle(OnThreadBackground<T> onThreadBackground, OnThreadSucess<T> onThreadSucess){
        ThreadUtils.executeBySingle(ThreadTaskTools.getTask(onThreadBackground,onThreadSucess));
    }

    /**
     * 运行任务到单次线程池中 ： 只运行执行一次任务
     * @param onThreadBackground 任务
     * @param onThreadSucess 成功回调
     * @param onThreadFail 失败回调
     * @param <T> 参数
     */
    public static <T> void runTaskBySingle(OnThreadBackground<T> onThreadBackground, OnThreadSucess<T> onThreadSucess, OnThreadFail onThreadFail){
        ThreadUtils.executeBySingle(ThreadTaskTools.getTask(onThreadBackground,onThreadSucess,onThreadFail));
    }

    /**
     * 运行任务到单次线程池中 ： 只运行执行一次任务
     * @param onThreadBackground 任务
     * @param onThreadSucess 成功回调
     * @param onThreadCancel 线程取消回调
     * @param onThreadFail 失败回调
     * @param <T> 参数
     */
    public static <T> void runTaskBySingle(OnThreadBackground<T> onThreadBackground, OnThreadSucess<T> onThreadSucess, OnThreadCancel onThreadCancel, OnThreadFail onThreadFail){
        ThreadUtils.executeBySingle(ThreadTaskTools.getTask(onThreadBackground,onThreadSucess,onThreadCancel,onThreadFail));
    }

    /* #######################################Thread Io Tools#########################################*/

}
